home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
comm
/
amigatcp.5
< prev
next >
Wrap
Text File
|
1989-03-18
|
64KB
|
2,823 lines
Path: xanth!ukma!mailrus!ulowell!page
From: page@swan.ulowell.edu (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i084: amigatcp - tcp/ip for the amiga, Part05/06
Message-ID: <12332@swan.ulowell.edu>
Date: 17 Mar 89 23:20:02 GMT
Organization: University of Lowell, Computer Science Dept.
Lines: 2812
Approved: page@swan.ulowell.edu
Submitted-by: rminnich@super.org (Ronald G. Minnich)
Posting-number: Volume 89, Issue 84
Archive-name: comm/amigatcp.5
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: Shell Archiver
# Run the following text with /bin/sh to create:
# amiga.c
# amigadev.c
# iproute.c
# telnetp.c
# This archive created: Fri Mar 17 17:58:48 1989
cat << \SHAR_EOF > amiga.c
/*
* Modifications to existing pc.c module are --
*
* Copyright (c) 1987
* Louis A. Mamakos
*
* This work, or any derivations thereof may be used for non-commercial
* purposes only. So there.
*/
/* OS- and machine-dependent stuff for the Commodore-Amiga 1000 */
#define AMIGAVERSION "3"
#include <exec/types.h>
#include <functions.h>
/* for Manx Aztec C, get func returns */
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/ports.h>
#include <exec/devices.h>
#include <exec/io.h>
#include <devices/console.h>
#include <devices/serial.h>
#include <devices/timer.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#include <stdio.h>
#include "machdep.h"
#include "amiga.h"
#include "mbuf.h"
#include "internet.h"
#include "iface.h"
#include "cmdparse.h"
#include "slip.h"
#include "timer.h"
#include "netuser.h"
#include "ip.h"
#include "tcp.h"
#ifdef TRACE
#include "trace.h"
#endif
static char *copyright_notice[2] = {
"AMIGA port of KA9Q TCP/IP (C) Copyright 1987 Louis A. Mamakos\r\n",
"for non-commercial, non-profic use only\r\n"};
struct asy asy[ASY_MAX];
void *malloc();
void setiss();
/* Interface list header */
struct interface *ifaces;
struct IntuitionBase *IntuitionBase;
static char banner[80];
static struct NewWindow nw = {
0, 0, 640, 200, /* left, top, (max) width, (max) height */
0, 1, /* detail pen, block pen */
0, /* IDCMP flags */
SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING |
SIZEBBOTTOM | ACTIVATE | NOCAREREFRESH, /* window flags */
NULL, NULL, /* gadget, checkmark */
(UBYTE *)&banner[0], /* title of window */
NULL, NULL, /* screen, bitmap */
200, 50, -1, -1, /* sizing limits */
WBENCHSCREEN, /* on the workbench */
};
APTR oldwindowptr;
struct Process *mytask;
struct MsgPort *keyboard, *consinp, *consoutp, *serinp, *seroutp,
*timerp;
struct IOExtSer serin, serout;
struct IOStdReq consin, consout;
struct timerequest tr;
struct Window *win;
char InputCharacter;
int timeropen, serialopen;
#ifdef AMIGADEVDRV
int DeviceSignal;
#endif
struct timer worktimer; /* this is NOT a timer.device timer */
void worker();
#ifdef LATTICE
extern struct { short error; char *msg; } os_errlist[];
extern int _OSERR, os_nerr;
#endif
static
clean(why)
char *why;
{
int i;
#ifdef AMIGADEVDRV
if (DeviceSignal >= 0)
FreeSignal(DeviceSignal);
#endif
if (timeropen)
CloseDevice(&tr);
if (serialopen)
CloseDevice(&serin);
if (win)
CloseWindow(win);
if (consinp)
DeletePort(consinp);
if (consoutp)
DeletePort(consoutp);
if (serinp)
DeletePort(serinp);
if (seroutp)
DeletePort(seroutp);
if (timerp)
DeletePort(timerp);
mytask->pr_WindowPtr = oldwindowptr;
if (why) {
myoserr(why);
}
exit(0);
}
myoserr(why)
char *why;
{
int i;
fprintf(stderr, "%s: ", why);
#ifdef LATTICE
fprintf(stderr, "%d: ", _OSERR);
for(i = 0; os_errlist[i].error < os_nerr; i++)
if (os_errlist[i].error == _OSERR)
fprintf(stderr, os_errlist[i].msg);
#endif
fprintf(stderr, "\r\n");
}
/* Called at startup time to set up console I/O, memory heap */
ioinit()
{
extern char major_rev[], minor_rev[];
struct Screen *scr;
mytask = (struct Process *) FindTask((char *) NULL);
oldwindowptr = mytask->pr_WindowPtr;
mytask->pr_WindowPtr = (APTR) -1; /* disable DOS requestors */
if ((IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", 33L)) == NULL)
clean("No intuition: Version 1.2 of Amiga Systems Software required");
sprintf(banner,
#ifdef AMIGADEVDRV
"KA9Q Internet Protocol Package, v%s.%s (Amiga version %sD)",
#else
"KA9Q Internet Protocol Package, v%s.%s (Amiga version %s)",
#endif
major_rev, minor_rev, AMIGAVERSION);
/*
* Try to determine the size of the workbench screen
*/
scr = malloc(sizeof(struct Screen));
if (scr==NULL)
clean("Can't alloc screen");
if (GetScreenData(scr, (ULONG) sizeof(struct Screen),
WBENCHSCREEN, NULL) == TRUE) {
nw.Width = scr->Width;
nw.Height = scr->Height-20;
nw.TopEdge = 19;
} else
fprintf(stderr, "Can't GetScreenData()\n");
free((char *)scr);
if ((win = OpenWindow(&nw)) == NULL)
clean("Can't open window");
if ((consinp = CreatePort("net:console in", 0L)) == NULL)
clean("Can't create console port");
if ((consoutp = CreatePort("net:console out", 0L)) == NULL)
clean("Can't create console port");
if ((timerp = CreatePort("net:timer", 0L)) == NULL)
clean("Can't create timer port");
consin.io_Data = (APTR) win;
consin.io_Length = sizeof(struct Window);
if (OpenDevice("console.device", 0L, &consin, 0L) != 0L)
clean("Can't open console device");
consout = consin;
consin.io_Message.mn_ReplyPort = consinp;
consin.io_Length = 1;
consin.io_Data = (APTR) &InputCharacter;
consin.io_Command = CMD_READ;
SendIO(&consin);
consout.io_Message.mn_ReplyPort = consoutp;
consout.io_Command = CMD_WRITE;
/* create and start up timer */
tr.tr_node.io_Message.mn_ReplyPort = timerp;
if (OpenDevice("timer.device", UNIT_VBLANK, &tr, 0L) != 0L)
clean("Can't open timer");
#ifdef AMIGADEVDRV
if ((DeviceSignal = AllocSignal(-1)) == -1)
clean("Can't allocate device signal");
#endif
timeropen++;
tr.tr_node.io_Command = TR_GETSYSTIME;
DoIO(&tr);
#ifdef DEBUG
printf("System time is %ld\n", tr.tr_time.tv_secs);
#endif
setiss(tr.tr_time.tv_secs);
tr.tr_node.io_Command = TR_ADDREQUEST;
tr.tr_time.tv_secs = 0;
tr.tr_time.tv_micro = MSPTICK*1000L; /* convert to microseconds */
SendIO(&tr);
set_timer(&worktimer, 1500); /* set for 1.5 seconds */
worktimer.func = worker;
#ifdef AMIGADEVDRV
DriverInit(); /* install internet.device driver */
#endif
start_timer(&worktimer);
}
/* Called just before exiting to restore console state */
iostop()
{
while(ifaces != NULLIF){
if(ifaces->stop != NULLFP)
(*ifaces->stop)(ifaces);
ifaces = ifaces->next;
}
#ifdef AMIGADEVDRV
DriverShutdown();
#endif
clean((char *)0);
}
#define BUFMAXCNT 150
static char conbuf[BUFMAXCNT];
static int concnt = 0;
int
amigaputchar(c)
char c;
{
conbuf[concnt++] = c;
if ((c == '\n') || (concnt == BUFMAXCNT))
amigaflush();
return c;
}
amigaflush()
{
if (concnt == 0)
return;
consout.io_Data = (APTR) conbuf;
consout.io_Length = concnt;
consout.io_Command = CMD_WRITE;
DoIO(&consout);
concnt = 0;
}
/*
* Begin terrible, horrible hack. All output should be printed upon (into?)
* the window we opened before. Here goes nothing...
*/
void
printf(a, b, c, d, e, f, g, h, i, j, k)
char *a;
int b, c, d, e, f, g, h, i, j, k;
{
if (concnt)
amigaflush();
sprintf(conbuf, a, b, c, d, e, f, g, h, i, j, k);
consout.io_Data = (APTR) conbuf;
consout.io_Length = strlen(conbuf);
consout.io_Command = CMD_WRITE;
DoIO(&consout); /* no use in doing this async */
}
/* check active connections and update titles */
void
check_connections()
{
extern struct tcb *tcbs[NTCB];
register struct tcb *tcb;
register int i;
int newlisten, newopn;
static int listen = -1, opn = -1;
static msg[80];
newlisten = newopn = 0;
for(i=0; i<NTCB; i++)
for(tcb=tcbs[i]; tcb != NULLTCB; tcb = tcb->next)
if (tcb->state == LISTEN)
newlisten++;
else
newopn++;
if (newlisten != listen || newopn != opn) {
listen = newlisten;
opn = newopn;
sprintf(msg,
"Amiga Port by WA3YMH (TCP: listen: %d open: %d)", listen, opn);
SetWindowTitles(win, -1L, msg);
}
}
/* called every second or so */
void
worker()
{
check_connections();
start_timer(&worktimer);
}
#if 0
/* processes any messages that Intuition sends us */
void
Do_Intuition_Message(m)
register struct IntuiMessage *m;
{
ULONG class;
USHORT code, qualifier;
class = m->Class;
code = m->Code;
qualifier = m->Qualifier;
ReplyMsg((struct Message *) m); /* reply msg back to Intuition */
switch (class) {
case INTUITICKS:
check_connections();
break;
}
}
#endif
/*
* wait for something to happen
*/
eihalt()
{
register struct IntuiMessage *msg;
static ULONG mask = 0;
if (mask == 0L)
mask = 1L << consinp->mp_SigBit |
1L << serinp->mp_SigBit |
1L << timerp->mp_SigBit |
#ifdef AMIGDEVDRV
1L << DeviceSignal |
#endif
#if 0
1L << win->UserPort->mp_SigBit |
#endif
1L << seroutp->mp_SigBit;
(void) Wait(mask);
#if 0
while (msg = (struct IntuiMessage *)GetMsg(win->UserPort))
Do_Intuition_Message(msg);
#endif
}
/* checks the time then ticks and updates ISS */
void
check_time()
{
int32 iss();
if (CheckIO(&tr)) {
WaitIO(&tr);
(void) GetMsg(timerp);
tick();
(void)iss();
tr.tr_time.tv_secs = 0;
tr.tr_time.tv_micro = MSPTICK*1000L;
/* convert to microseconds */
SendIO(&tr);
}
}
/* Initialize asynch port "dev" */
/*
* We will make the bold and rash assumption that the asy link will be used
* for slip and slip-like stuff. That is, we assume that there is an
* an end-of-frame character that we can have the serial.device driver look
* for. Thus, we can fire up a single I/O request and have the whole frame
* come back at once.
*/
int
asy_init(dev, bufsize)
int16 dev;
unsigned bufsize;
{
char serinitstr[1];
int serinitlen;
serinitstr[0] = FR_END; /* initialize initialization string to a */
serinitlen = 1; /* frame end to flush receiver */
if (serialopen) {
printf("\namiga: Error - serial device already open.\n");
return 0;
}
if ((serinp = CreatePort("net:serin", 0L)) == NULL)
clean("Can't create serial input port");
if ((seroutp = CreatePort("net:serout", 0L)) == NULL)
clean("Can't create serial output port");
/*
* Open serial device.
*/
serin.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE; /* ? */
serin.io_Status = 0;
serin.io_RBufLen = bufsize;
asy[dev].speed = serin.io_Baud = 2400; /* default speed */
if (OpenDevice("serial.device", 0L, &serin, 0L) != 0L)
clean("Can't open serial device");
serialopen++;
serin.IOSer.io_Message.mn_ReplyPort = serinp;
serout = serin;
serout.IOSer.io_Message.mn_ReplyPort = seroutp;
asy[dev].buflen = bufsize;
/* alloc input buffer */
if((asy[dev].input_buffer = malloc(asy[dev].buflen)) == NULL)
clean("Can't allocate serial input buf");
serin.IOSer.io_Data = (APTR) asy[dev].input_buffer;
serin.IOSer.io_Length = asy[dev].buflen;
asy[dev].input_len = 0; /* clear input buffer */
serin.io_SerFlags = SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE;
serin.IOSer.io_Flags = 0;
SendIO(&serin);
serout.IOSer.io_Data = (APTR) serinitstr;
serout.IOSer.io_Length = serinitlen;
serout.IOSer.io_Command = CMD_WRITE;
serout.IOSer.io_Flags = 0;
serout.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE;
DoIO(&serout);
}
int
asy_stop(iface)
struct interface *iface;
{
if (iface->dev >= ASY_MAX) {
fprintf(stderr, "asy_stop: bad dev %d\n", iface->dev);
return;
}
AbortIO(&serin);
AbortIO(&serout);
CloseDevice(&serin);
free(asy[iface->dev].input_buffer); /* release buffer */
serialopen--;
}
/* Set asynch line speed */
int
asy_speed(dev,speed)
int dev;
int speed;
{
if (serialopen == 0)
return;
AbortIO(&serin);
WaitIO(&serin);
(void) GetMsg(serinp);
asy[dev].speed = serin.io_Baud = speed;
serin.io_ReadLen = 8;
serin.io_WriteLen = 8;
serin.io_StopBits = 1;
serin.io_TermArray.TermArray0 = serin.io_TermArray.TermArray1 =
(ULONG)FR_END << 24 | (ULONG)FR_END << 16 | FR_END << 8 | FR_END;
serin.IOSer.io_Command = SDCMD_SETPARAMS;
serin.IOSer.io_Flags = 0;
DoIO(&serin);
if (serin.IOSer.io_Error)
printf("Bad I/O status %d on SETPARAMS\n",
serin.IOSer.io_Error);
serin.IOSer.io_Command = CMD_READ;
serin.IOSer.io_Data = (APTR) asy[dev].input_buffer;
serin.IOSer.io_Length = asy[dev].buflen;
asy[dev].input_len = 0; /* clear input buffer */
serin.io_SerFlags = SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE;
serin.IOSer.io_Flags = 0; /* no quick I/O */
SendIO(&serin);
}
/* Send a buffer to serial transmitter */
asy_output(dev,buf,cnt)
unsigned dev;
char *buf;
unsigned short cnt;
{
/*
* We 'know' that the transmitter is ready since we would not have
* been called unless the previous I/O has been completed.
*/
WaitIO(&serout);
GetMsg(seroutp);
serout.IOSer.io_Data = (APTR) buf;
serout.IOSer.io_Length = cnt;
serout.io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE;
serout.IOSer.io_Flags = 0; /* no quick I/O */
serout.IOSer.io_Command = CMD_WRITE;
SendIO(&serout);
}
/* Read characters from the keyboard, translating them to "real" ASCII
* If none are ready, return the -1 from kbraw()
*/
kbread()
{
char c;
if (CheckIO(&consin)) {
WaitIO(&consin);
(void) GetMsg(consinp);
c = InputCharacter;
consin.io_Length = 1;
consin.io_Data = (APTR) &InputCharacter;
consin.io_Command = CMD_READ;
SendIO(&consin); /* start next read up */
return (c & 0xff);
}
return -1; /* nuthin here */
}
/* Receive characters from asynch line
* Returns count of characters read
*/
unsigned
asy_recv(dev,buf,cnt)
int dev;
char *buf;
unsigned cnt;
{
register int actual = 0;
register long error;
if (asy[dev].input_len == 0) { /* if buffer is empty.. */
if (CheckIO(&serin) == NULL) /* see if I/O has completed */
return 0; /* nope, not yet. */
if (error = WaitIO(&serin))
printf("(SERIN) WaitIO returns %d\n", error);
if (serin.IOSer.io_Error)
printf("Bad I/O stat %d (SERIN)\n",
serin.IOSer.io_Error);
(void) GetMsg(serinp);
/* input has completed. fill in state variables */
asy[dev].input_len = serin.IOSer.io_Actual;
asy[dev].input_p = asy[dev].input_buffer;
#ifdef TRACE
if (trace & 0x40000000) {
int a, n, l = asy[dev].input_len;
unsigned char *b = asy[dev].input_buffer;
a = 0;
printf("Raw serial input:\r\n");
while (l) {
n = min(l, 16);
fmtline(a, b, n);
a += n;
b += n;
l -= n;
}
fflush(stdout);
}
#endif
}
if (asy[dev].input_len) { /* any chars in buffer left? */
actual = min(asy[dev].input_len, cnt);
if (actual == 1)
*buf = *asy[dev].input_p; /* usual case */
else
movmem(asy[dev].input_p, buf, actual);
asy[dev].input_len -= actual;
asy[dev].input_p += actual;
}
if (asy[dev].input_len == 0) { /* if buffer is now empty */
serin.IOSer.io_Command = CMD_READ;
serin.IOSer.io_Data = (APTR) asy[dev].input_buffer;
serin.IOSer.io_Length = asy[dev].buflen;
serin.io_SerFlags =
SERF_XDISABLED|SERF_EOFMODE|SERF_RAD_BOOGIE;
serin.IOSer.io_Flags = 0; /* no quick I/O */
SendIO(&serin);
}
return actual;
}
int
stxrdy(dev)
{
return (CheckIO(&serout) != NULL);
}
/* Create a directory listing in a temp file and return the resulting file
* descriptor. If full == 1, give a full listing; else return just a list
* of names.
*
* This function is very dependent on the workings of Aztec standard I/O;
* it uses their mechanism for generating and deleting temporary files.
*/
FILE *
dir(path,full)
char *path;
int full;
{
/*return (FILE *)NULL;*/
return(0L);
}
#if 0
bcmp(a,b,n)
register char *a,*b;
register int16 n;
{
while(n-- != 0){
if(*a++ != *b++)
return 1;
}
return 0;
}
#endif
SHAR_EOF
cat << \SHAR_EOF > amigadev.c
/*
* Copyright (C) 1987
* Louis A. Mamakos WA3YMH
* All rights reserved.
*
* This code may not be redistributed, sold, included on any collection of
* software which is sold. Use of this software is restricted to inclusion
* in the KA9Q TCP/IP software package for use on a Commodore-Amiga system.
* Commercial use is prohibited. Only educational and Amateur Packet Radio
* use is allowed.
*/
#ifdef AMIGADEVDRV
/*
* This module is the meat of the Amiga 'internet.device' device driver. There
* are assembly language stubs in devstub.asm that call this module when user
* program access the device driver. Remember: the tasks running this code are
* not our own!
*/
#include <stdio.h>
/* Amiga system definitions */
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/io.h>
#include <exec/devices.h>
#include <exec/errors.h>
/* get definitions of KA9Q TCP/IP protocol stuff... */
#include "machdep.h"
#include "timer.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "icmp.h"
#include "ip.h"
#include "tcp.h"
#include "trace.h"
#include "session.h"
/* device driver specific definitions */
#define ListEmpty(x) (! ((x)->lh_Head->ln_Succ))
#include "inetdev.h"
#ifdef TRACE
#define tracedev(x) \
if (trace & TRACE_DEVICE) printf(x)
#define tracedev2(x,y) \
if (trace & TRACE_DEVICE) printf(x,y)
#define tracedev3(x,y,z) \
if (trace & TRACE_DEVICE) printf(x,y,z)
#define tracedev4(x,y,z,zz) \
if (trace & TRACE_DEVICE) printf(x,y,z,zz)
#endif
char *malloc();
extern void DSClose(), DSBeginIO(), DSAbortIO();
extern struct InternetBase *DSOpen();
extern long DSExpunge();
void indev_tcp_r_upcall(), indev_tcp_t_upcall(), indev_s_upcall();
struct SignalSemaphore INLock;
struct Library *MakeLibrary();
/* for open requests */
int nopens; /* from iface */
struct IOINETReq *iob = NULL;
int unit_spec;
struct InternetBase * dev;
int OpenIt = 0,
CN1 = 0,
IOpenedIt = 0;
extern int DeviceSignal;
extern struct Process *mytask;
printlist(l)
struct List *l;
{
printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail,
l->lh_TailPred);
}
/*
* Initialize and install the Amiga 'internet.device'.
*/
void
DriverInit()
{
char *foo[10];
int success;
static int WeWereHere;
int x;
tracedev("DriverInit");
x = WeWereHere;
WeWereHere = 1;
if (x)
{
printf("you tried to add the driver twice!!!\n");
return;
}
foo[0] = (char *) &DSOpen;
foo[1] = (char *) &DSClose;
foo[2] = (char *) &DSExpunge;
foo[3] = (char *) NULL;
foo[4] = (char *) &DSBeginIO;
foo[5] = (char *) &DSAbortIO;
/* add any other custom routines here */
foo[6] = (char *) -1;
InternetBase = (struct InternetBase *)
MakeLibrary(&foo[0], (char *) NULL, (char *) NULL,
(long) sizeof(struct InternetBase), (char *) NULL);
if (InternetBase == (struct InternetBase *) 0) {
/* display alert? */
return;
}
InitSemaphore(&(INLock));
ObtainSemaphore(&(INLock));
InitSemaphore(&(InternetBase->ib_lock));
InternetBase->ib_lock.ss_Link.ln_Pri = 0;
InternetBase->ib_lock.ss_Link.ln_Name = "internet.device lock";
NewList(&InternetBase->ib_Units);
InternetBase->ib_Units.lh_Type = NT_UNKNOWN;
InternetBase->lib.lib_Node.ln_Type = NT_DEVICE;
InternetBase->lib.lib_Node.ln_Pri = 0;
InternetBase->lib.lib_Node.ln_Name = "internet.device";
InternetBase->lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
InternetBase->lib.lib_Version = IN_VERSION;
InternetBase->lib.lib_Revision = IN_REVISION;
InternetBase->lib.lib_IdString =
(APTR) "internet.device 23 May 1987\r\n";
success = AddDevice(InternetBase);
Savea4();
OpenIt = 0;
IOpenedIt = 0;
nopens = 1;
CN1 = 5;
if (success != 0)
myoserr("driver open");
printf("driver added returned %d\n",success);
}
void
DriverShutdown()
{
long error;
extern long *RemoveDevice();
if (!InternetBase)
return;
if (error = RemDevice(InternetBase))
printf("Can't remove device: error %ld\n", error);
}
struct InternetBase *
NetDevOpen(mdev, munit_spec, miob, mflags)
struct InternetBase *mdev;
struct IOINETReq *miob;
ULONG munit_spec, mflags;
{
iob = miob;
dev = mdev;
unit_spec = munit_spec;
if (IOpenedIt == 1)
{
CN1++;
return NULL;
}
OpenIt = 1;
Permit();
while (IOpenedIt == 0);
Forbid();
IOpenedIt = 0;
return dev;
}
check_driver()
{
register struct INET_Unit *unit;
register struct tcb *tcb;
if (OpenIt != 0)
{
printf("open request!\n");
switch (unit_spec) {
case INET_UNIT_TCP:
case INET_UNIT_UDP:
break;
default:
iob->io_Error = IOERR_OPENFAIL;
iob->io_Device = NULL;
iob->io_Unit = NULL;
OpenIt = 0;
IOpenedIt = 1;
goto doneopen;
}
if ((unit = (struct INET_Unit *)
malloc(sizeof(struct INET_Unit))) == NULL) {
iob->io_Error = IOERR_OPENFAIL;
OpenIt = 0;
IOpenedIt = 1;
goto doneopen;
}
tracedev2("malloc ok %x\n", unit);
iob->io_Unit = unit;
iob->io_Device = (struct Device *)dev;
dev->lib.lib_OpenCnt++;
unit->iu_Unit.ln_Type = NT_UNKNOWN;
unit->iu_Unit.ln_Pri = 0;
NewList(&unit->iu_Input);
NewList(&unit->iu_Output);
printf("newlist ok\n");
unit->iu_Input.lh_Type = NT_UNKNOWN; /* gee, what do we really */
unit->iu_Output.lh_Type = NT_UNKNOWN; /* call these... */
unit->iu_user = iob->io_Offset; /* always returned in Offset */
unit->iu_Act_Input = NULL;
unit->iu_Act_Output = NULL;
iob->io_lsocket.address = ip_addr;
iob->io_lsocket.port = lport++;
AddTail(&InternetBase->ib_Units, &unit->iu_Unit);
/* perform protocol specific open functions */
printf("addtail\n");
switch (unit_spec) {
case INET_UNIT_TCP:
/* Forbid(); */
tcb = open_tcp(&(iob->io_lsocket), &(iob->io_fsocket),
(USHORT) iob->io_Offset, (USHORT) iob->io_TCP_Window,
indev_tcp_r_upcall, indev_tcp_t_upcall, indev_s_upcall,
iob->io_INET_TOS, (char *)unit);
/* Permit();*/
if (tcb == NULL)
goto fail;
unit->iu_Unit.ln_Name = "TCP Connection";
unit->iu_type = INET_UNIT_TCP;
unit->iu_ccb = tcb;
printf("cpopen is %d\n", tcb);
break;
default:
fail:
iob->io_Error = IOERR_OPENFAIL;
dev->lib.lib_OpenCnt--;
Remove(unit);
free(unit);
OpenIt = 0;
IOpenedIt = 1;
goto doneopen;
}
tracedev2("dev is %d\n", dev);
OpenIt = 0;
IOpenedIt = 1;
}
doneopen:
/* spin until that other guy is all done. We will not get through
* this spin until the other guy has done a Forbid() and
* then a Permit(), since the IopenedIt gets cleared
* AFTER the Forbid(). Sorry i do not use semaphores but
* i do not have 1.2 autodocs so am not totally up on their
* use.
*/
while (IOpenedIt);
}
CheckTcp()
{
struct Node *head = InternetBase->ib_Units.lh_Head;
struct INET_Unit *unit = (struct INET_Unit *) head;
struct tcb *tcb;
/* let the other guys in */
ReleaseSemaphore(&(INLock));
eihalt();
ObtainSemaphore(&(INLock));
tracedev("start checktcp\n");
tracedev4("heda %x Pred is %x Succ is %x\n", head,head->ln_Pred, head->ln_Succ);
for (;unit->iu_Unit.ln_Succ;unit = unit->iu_Unit.ln_Succ)
{
tracedev3("checktcp: %x Succ %d\n", unit, unit->iu_Unit.ln_Succ);
if (unit->iu_type != INET_UNIT_TCP)
{
tracedev("not a tcp\n");
continue;
}
tcb = (struct tcb *) unit->iu_ccb;
if (tcb == NULL)
{
tracedev("NULL tcb in unit\n");
continue;
}
if (tcb->state == ESTABLISHED)
{
tracedev("unit state is established!\n");
/* continue;*/
}
tracedev("do the upcall\n");
do_tupcall(tcb, 512); /* for now- it wil do the right thing */
if (tcb->rcvcnt > 0)
do_rupcall(tcb, tcb->rcvcnt);
}
tracedev("done checktcp\n");
/* ReleaseSemaphore(&(INLock));*/
}
void DevClose(dev, iob)
struct InternetBase *dev;
struct IOINETReq *iob;
{
register struct INET_Unit *unit;
struct tcb *tcb;
unit = iob->io_Unit;
tcb = unit->iu_ccb;
del_tcp(tcb);
Remove(unit);
free(unit);
iob->io_Unit = NULL;
iob->io_Device = (struct Device *)dev;
dev->lib.lib_OpenCnt--;
/* remove iu_Unit from ib_Units list */
/* decrement library use count */
/* free unit structure */
/* delete TCP/UDP connection del_tcp()/del_udp() */
}
long DevExpunge(dev)
struct InternetBase *dev;
{
register char *m;
register long len;
if (InternetBase->lib.lib_OpenCnt) {
InternetBase->lib.lib_Flags |= LIBF_DELEXP;
return 0;
}
Remove(InternetBase); /* remove from library list */
len = InternetBase->lib.lib_NegSize + InternetBase->lib.lib_PosSize;
m = (char *) ((ULONG)InternetBase - InternetBase->lib.lib_NegSize);
FreeMem(m, len);
return 0;
}
#define C_IMMED (1<<0)
#define C_READ (1<<1)
#define C_WRITE (1<<2)
void cmd_Invalid(), cmd_Reset(), cmd_Read(), cmd_Write(), cmd_Update(),
cmd_Clear(), cmd_Stop(), cmd_Start(), cmd_Flush(), PerformIO();
struct Commands {
void (*cmd_func)();
int cmd_flags;
} commands [] = {
{ cmd_Invalid, C_IMMED }, /* invalid */
{ cmd_Reset, C_IMMED }, /* CMD_RESET */
{ cmd_Read, C_READ }, /* CMD_READ */
{ cmd_Write, C_WRITE }, /* CMD_WRITE */
{ cmd_Update, C_WRITE }, /* CMD_UPDATE */
{ cmd_Clear, C_IMMED }, /* CMD_CLEAR */
{ cmd_Stop, C_IMMED }, /* CMD_STOP */
{ cmd_Start, C_IMMED }, /* CMD_START */
{ cmd_Flush, C_IMMED }, /* CMD_FLUSH */
};
/* define last valid command */
#define MAX_IO_COMMAND CMD_FLUSH
/* BeginIO is called to begin processing of the I/O request */
void DevBeginIO(iob, dev)
struct IOINETReq *iob;
struct InternetBase *dev;
{
register struct Commands *cmd;
register struct INET_Unit *unit = iob->io_Unit;
ObtainSemaphore(&(INLock));
if (iob->io_Command > MAX_IO_COMMAND) {
cmd_Invalid(iob, iob->io_Unit);
goto done;
}
tracedev("io. ObtainSme\n");
tracedev("got it\n");
cmd = &commands[iob->io_Command];
tracedev2("cmd is %d\n",iob->io_Command);
tracedev2("flags %d\n", iob->io_Flags);
if ((cmd->cmd_flags & C_IMMED) == 0) {
/*
* Code for commands which can queue
*/
if ((cmd->cmd_flags & C_READ)/* && (unit->iu_Act_Input)*/) {
AddTail(&unit->iu_Input, iob);
iob->io_Flags &= ~IOF_QUICK;
iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
tracedev3("added %d to read queue of unit %d\n", iob, unit);
goto done;
}
if ((cmd->cmd_flags & C_WRITE)/* && (unit->iu_Act_Output)*/) {
AddTail(&unit->iu_Output, iob);
iob->io_Flags &= ~IOF_QUICK;
iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
tracedev3("added %d to write queue of unit %d\n", iob, unit);
goto done;
}
}
PerformIO(iob, unit);
done: tracedev4("flags QUI %x ~QUI %x %d\n", IOF_QUICK, ~IOF_QUICK,
iob->io_Flags);
Signal(mytask, DeviceSignal);
ReleaseSemaphore(&(INLock));
}
void DevAbortIO(iob, dev)
struct IOINETReq *iob;
struct InternetBase *dev;
{
printf("DevAbortIo\n");
}
void
PerformIO(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = 0;
iob->io_Actual = 0;
(*commands[iob->io_Command].cmd_func)(iob, unit);
}
void
TermIO(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
struct tcb *tcb;
tcb = (struct tcb *) unit->iu_ccb;
iob->io_OldState = iob->io_State;
iob->io_State = tcb->state;
if ((iob->io_Flags & IOF_QUICK) == 0)
/* not quick I/O */
ReplyMsg(&iob->io_Message);
}
void
cmd_Invalid(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Reset(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Read(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Write(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Update(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Clear(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Stop(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Start(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
void
cmd_Flush(iob, unit)
struct IOINETReq *iob;
struct INET_Unit *unit;
{
iob->io_Error = IOERR_NOCMD;
TermIO(iob, unit);
}
/* TCP receiver upcall routine. Called with TCB pointer and number of bytes
available */
do_rupcall(tcb, cnt)
struct tcb *tcb;
int16 cnt;
{
struct mbuf *bp;
register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
int amount, recamount;
struct IOINETReq *iob;
/* ObtainSemaphore(&(INLock));*/
if (ListEmpty(&(unit->iu_Input)))
goto done;
iob = unit->iu_Act_Input = unit->iu_Input.lh_Head;
tracedev4("dev rupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
if (iob != NULL)
{
Remove(iob);
amount = min(cnt, iob->io_Length);
tracedev3("call recv_tcp %d bytes avail %d\n", amount, cnt);
recamount = recv_tcp(tcb, &bp, amount);
iob->io_Actual = dqdata(bp, iob->io_Data, recamount);
tracedev2("recv_tcp after got %d bytes\n", iob->io_Actual);
TermIO(iob, unit);
/* ReplyMsg(&(iob->io_Message));*/
}
done:
/* ReleaseSemaphore(&(INLock)); */
}
/* TCP receiver upcall routine. Called with TCB pointer and number of bytes
available */
void
indev_tcp_r_upcall(tcb, cnt)
struct tcb *tcb;
int16 cnt;
{
/* ObtainSemaphore(&(INLock));*/
do_rupcall(tcb, 512);
/* ReleaseSemaphore(&(INLock)); */
}
/* TCP transmitter upcall routine. Called with TCB pointer and number of bytes
free in send window */
do_tupcall(tcb, avail)
struct tcb *tcb;
int16 avail;
{
struct mbuf *bp, *qdata();
register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
int amount;
struct IOINETReq *iob;
if (ListEmpty(&(unit->iu_Output)))
goto done;
tracedev("non-empty Output\n");
iob = unit->iu_Act_Output = unit->iu_Output.lh_Head;
tracedev4("dev tupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
if (iob != NULL)
{
Remove(iob);
amount = min(avail, iob->io_Length);
tracedev3("t_upcall- send_tcp for addr %x %d bytes\n",iob->io_Data,
amount);
bp = qdata(iob->io_Data, amount);
iob->io_Actual = send_tcp(tcb, bp);
tracedev2("send_tcp after got %d bytes\n", iob->io_Actual);
TermIO(iob, unit);
/* ReplyMsg(&(iob->io_Message));*/
unit->iu_Act_Output = NULL;
}
done:
}
void
indev_tcp_t_upcall(tcb, avail)
struct tcb *tcb;
int16 avail;
{
/* ObtainSemaphore(&(INLock));*/
do_tupcall(tcb, avail);
/* ReleaseSemaphore(&(INLock)); */
}
void
indev_s_upcall(tcb, old, new)
struct tcb *tcb;
char old, new;
{
register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
char notify = 0;
extern char *tcpstates[];
extern char *reasons[];
extern char *unreach[];
extern char *exceed[];
/* Can't add a check for unknown connection here, it would loop
* on a close upcall! We're just careful later on.
*/
if(unit != NULL)
notify = 1;
switch(new){
case CLOSE_WAIT:
if(notify)
printf("%s\r\n",tcpstates[new]);
close_tcp(tcb);
break;
case CLOSED: /* court adjourned */
if(notify){
printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
if(tcb->reason == NETWORK){
switch(tcb->type){
case DEST_UNREACH:
printf(": %s unreachable",unreach[tcb->code]);
break;
case TIME_EXCEED:
printf(": %s time exceeded",exceed[tcb->code]);
break;
}
}
printf(")\r\n");
}
del_tcp(tcb);
break;
default:
if(notify)
printf("%s\r\n",tcpstates[new]);
break;
}
fflush(stdout);
}
#endif
SHAR_EOF
cat << \SHAR_EOF > iproute.c
/* Lower half of IP, consisting of gateway routines
* Includes routing and options processing code
*/
#include <stdio.h>
#include "machdep.h"
#include "mbuf.h"
#include "internet.h"
#include "timer.h"
#include "netuser.h"
#include "ip.h"
#include "icmp.h"
#include "iface.h"
#ifdef TRACE
#include "trace.h"
#endif
struct route *routes[32][NROUTE]; /* Routing table */
struct route r_default; /* Default route entry */
int32 ip_addr;
struct ip_stats ip_stats;
/* Route an IP datagram. This is the "hopper" through which all IP datagrams,
* coming or going, must pass.
*
* This router is a temporary hack, since it only does host-specific or
* default routing (no hierarchical routing yet).
*
* "rxbroadcast" is set to indicate that the packet came in on a subnet
* broadcast. The router will kick the packet upstairs regardless of the
* IP destination address.
*/
void
ip_route(bp,rxbroadcast)
struct mbuf *bp;
char rxbroadcast; /* True if packet had link broadcast address */
{
register struct ip_header *ip; /* IP header being processed */
int16 ip_len; /* IP header length */
int16 buflen; /* Length of mbuf */
int16 length; /* Total datagram length */
int32 target; /* Target IP address */
int32 gateway; /* Gateway IP address */
register struct route *rp; /* Route table entry */
struct route *rt_lookup();
int opi; /* Index into options field */
int opt_len; /* Length of current option */
int strict; /* Strict source routing flag */
struct mbuf *sbp; /* IP header for fragmenting */
int16 fl_offs; /* fl_offs field of datagram */
int16 offset; /* Offset of fragment */
char precedence; /* Extracted from tos field */
char delay;
char throughput;
char reliability;
ip_stats.total++;
buflen = len_mbuf(bp);
if(buflen < sizeof(struct ip_header)){
/* The packet is shorter than a legal IP header */
ip_stats.runt++;
free_p(bp);
return;
}
ip = (struct ip_header *)bp->data;
length = ntohs(ip->length);
if(buflen > length){
/* Packet has excess garbage (e.g., Ethernet padding); trim */
if(bp->next == NULLBUF){
/* One mbuf, just adjust count */
bp->cnt = length;
} else {
struct mbuf *nbp;
/* Copy to a new one */
nbp = copy_p(bp,length);
free((char *)bp);
bp = nbp;
ip = (struct ip_header *)bp->data;
}
}
ip_len = lonibble(ip->v_ihl) * sizeof(int32);
if(ip_len < sizeof(struct ip_header)){
/* The IP header length field is too small */
ip_stats.length++;
free_p(bp);
return;
}
if(cksum(NULLHEADER,bp,ip_len) != 0){
/* Bad IP header checksum; discard */
ip_stats.checksum++;
free_p(bp);
return;
}
if(hinibble(ip->v_ihl) != IPVERSION){
/* We can't handle this version of IP */
ip_stats.version++;
free_p(bp);
return;
}
/* See if it's a broadcast or addressed to us, and kick it upstairs */
if(ntohl(ip->dest) == ip_addr || rxbroadcast){
#ifdef GWONLY
/* We're only a gateway, we have no host level protocols */
if(!rxbroadcast)
icmp_output(bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
free_p(bp);
#else
#ifdef TRACE
if(trace & TRACE_SELF && ntohl(ip->source) == ip_addr){
printf("loopback:\r\n");
if((trace & TRACE_HDR) > 2)
ip_dump(bp);
if(trace & TRACE_DUMP)
hexdump(bp);
fflush(stdout);
}
#endif
ip_recv(bp,rxbroadcast);
#endif
return;
}
/* If we get here, we must forward the packet.
* Process options, if any. Also compute length of secondary IP
* header in case fragmentation is needed later
*/
strict = 0;
for(opi = sizeof(struct ip_header);opi < ip_len; opi += opt_len){
char *opt; /* Points to current option */
int opt_type; /* Type of current option */
int pointer; /* Pointer field of current option */
int32 *addr; /* Pointer to an IP address field in option */
opt = (char *)ip + opi;
opt_type = opt[0] & OPT_NUMBER;
/* Handle special 1-byte do-nothing options */
if(opt_type == IP_EOL)
break; /* End of options list, we're done */
if(opt_type == IP_NOOP){
opt_len = 1; /* No operation, skip to next option */
continue;
}
/* Other options have a length field */
opt_len = opt[1] & 0xff;
/* Process options */
switch(opt_type){
case IP_SSROUTE:/* Strict source route & record route */
strict = 1;
case IP_LSROUTE:/* Loose source route & record route */
/* Source routes are ignored unless the datagram appears to
* be for us
*/
if(ntohl(ip->dest) != ip_addr)
continue;
case IP_RROUTE: /* Record route */
pointer = (opt[2] & 0xff) - 1;
if(pointer + sizeof(int32) <= opt_len){
/* Insert our address in the list */
addr = (int32 *)&opt[pointer];
if(opt_type != IP_RROUTE)
/* Old value is next dest only for source routing */
ip->dest = *addr;
*addr = htonl(ip_addr);
opt[2] += 4;
} else {
/* Out of space; return a parameter problem and drop */
union icmp_args icmp_args;
icmp_args.unused = 0;
icmp_args.pointer = sizeof(struct ip_header) + opi;
icmp_output(bp,PARAM_PROB,0,&icmp_args);
free_p(bp);
return;
}
break;
}
}
/* Decrement TTL and discard if zero */
if(--ip->ttl == 0){
/* Send ICMP "Time Exceeded" message */
icmp_output(bp,TIME_EXCEED,0,NULLICMP);
free_p(bp);
return;
}
/* Note this address may have been modified by source routing */
target = ntohl(ip->dest);
/* Look up target address in routing table */
if((rp = rt_lookup(target)) == NULLROUTE){
/* No route exists, return unreachable message */
icmp_output(bp,DEST_UNREACH,HOST_UNREACH,NULLICMP);
free_p(bp);
return;
}
/* Find gateway; zero gateway in routing table means "send direct" */
if(rp->gateway == (int32)0)
gateway = target;
else
gateway = rp->gateway;
if(strict && gateway != target){
/* Strict source routing requires a direct entry */
icmp_output(bp,DEST_UNREACH,ROUTE_FAIL,NULLICMP);
free_p(bp);
return;
}
precedence = PREC(ip->tos);
delay = ip->tos & DELAY;
throughput = ip->tos & THRUPUT;
reliability = ip->tos & RELIABILITY;
if(length <= rp->interface->mtu){
/* Datagram smaller than interface MTU; send normally */
/* Recompute header checksum */
ip->checksum = 0;
ip->checksum = cksum(NULLHEADER,bp,ip_len);
(*rp->interface->send)(bp,rp->interface,gateway,
precedence,delay,throughput,reliability);
return;
}
/* Fragmentation needed */
fl_offs = ntohs(ip->fl_offs);
if(fl_offs & DF){
/* Don't Fragment set; return ICMP message and drop */
icmp_output(bp,DEST_UNREACH,FRAG_NEEDED,NULLICMP);
free_p(bp);
return;
}
/* Create copy of IP header for each fragment */
sbp = copy_p(bp,ip_len);
pullup(&bp,NULLCHAR,ip_len);
length -= ip_len;
/* Create fragments */
offset = (fl_offs & F_OFFSET) << 3;
while(length != 0){
int16 fragsize; /* Size of this fragment's data */
struct mbuf *f_header; /* Header portion of fragment */
struct ip_header *fip; /* IP header */
struct mbuf *f_data; /* Data portion of fragment */
f_header = copy_p(sbp,ip_len);
fip = (struct ip_header *)f_header->data;
fip->fl_offs = htons(offset >> 3);
if(length + ip_len <= rp->interface->mtu){
/* Last fragment; send all that remains */
fragsize = length;
} else {
/* More to come, so send multiple of 8 bytes */
fragsize = (rp->interface->mtu - ip_len) & 0xfff8;
fip->fl_offs |= htons(MF);
}
fip->length = htons(fragsize + ip_len);
/* Recompute header checksum */
fip->checksum = 0;
fip->checksum = cksum(NULLHEADER,f_header,ip_len);
/* Extract portion of data and link in */
f_data = copy_p(bp,fragsize);
pullup(&bp,NULLCHAR,fragsize);
f_header->next = f_data;
(*rp->interface->send)(f_header,rp->interface,gateway,
precedence,delay,throughput,reliability);
offset += fragsize;
length -= fragsize;
}
free_p(sbp);
}
/* Add an entry to the IP routing table. Returns 0 on success, -1 on failure */
int
rt_add(target,bits,gateway,metric,interface)
int32 target; /* Target IP address prefix */
unsigned bits; /* Size of target address prefix in bits (0-32) */
int32 gateway;
int metric;
struct interface *interface;
{
struct route *rp,**hp,*rt_lookup();
int16 hash_ip(),i;
char *malloc();
if(interface == NULLIF)
return -1;
/* Zero bits refers to the default route */
if(bits == 0){
rp = &r_default;
} else {
if(bits > 32)
bits = 32;
/* Mask off don't-care bits */
for(i=31;i >= bits;i--)
target &= ~(0x80000000 >> i);
/* Search appropriate chain for existing entry */
for(rp = routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
if(rp->target == target)
break;
}
}
if(rp == NULLROUTE){
/* The target is not already in the table, so create a new
* entry and put it in.
*/
if((rp = (struct route *)malloc(sizeof(struct route))) == NULLROUTE)
return -1; /* No space */
/* Insert at head of table */
rp->prev = NULLROUTE;
hp = &routes[bits-1][hash_ip(target)];
rp->next = *hp;
if(rp->next != NULLROUTE)
rp->next->prev = rp;
*hp = rp;
}
rp->target = target;
rp->gateway = gateway;
rp->metric = metric;
rp->interface = interface;
return 0;
}
/* Remove an entry from the IP routing table. Returns 0 on success, -1
* if entry was not in table.
*/
int
rt_drop(target,bits)
int32 target;
unsigned bits;
{
register struct route *rp;
struct route *rt_lookup();
unsigned i;
if(bits == 0){
/* Nail the default entry */
r_default.interface = NULLIF;
return 0;
}
if(bits > 32)
bits = 32;
/* Mask off don't-care bits */
for(i=31;i > bits;i--)
target &= ~(0x80000000 >> i);
/* Search appropriate chain for existing entry */
for(rp = routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
if(rp->target == target)
break;
}
if(rp == NULLROUTE)
return -1; /* Not in table */
if(rp->next != NULLROUTE)
rp->next->prev = rp->prev;
if(rp->prev != NULLROUTE)
rp->prev->next = rp->next;
else
routes[bits-1][hash_ip(target)] = rp->next;
free((char *)rp);
return 0;
}
/* Compute hash function on IP address */
static int16
hash_ip(addr)
register int32 addr;
{
register int16 ret;
ret = hiword(addr);
ret ^= loword(addr);
ret %= NROUTE;
return ret;
}
#ifndef GWONLY
/* Given an IP address, return the MTU of the local interface used to
* reach that destination. This is used by TCP to avoid local fragmentation
*/
int16
ip_mtu(addr)
int32 addr;
{
register struct route *rp;
struct route *rt_lookup();
rp = rt_lookup(addr);
if(rp != NULLROUTE && rp->interface != NULLIF)
return rp->interface->mtu;
else
return 0;
}
#endif
/* Look up target in hash table, matching the entry having the largest number
* of leading bits in common. Return default route if not found;
* if default route not set, return NULLROUTE
*/
static struct route *
rt_lookup(target)
int32 target;
{
register struct route *rp;
int16 hash_ip();
unsigned bits;
for(bits = 32;bits != 0; bits--){
if(bits != 32)
target &= ~(0x80000000 >> bits);
for(rp = routes[bits-1][hash_ip(target)];rp != NULLROUTE;rp = rp->next){
if(rp->target == target)
return rp;
}
}
if(r_default.interface != NULLIF)
return &r_default;
else
return NULLROUTE;
}
/* Internet checksum routines
* Improved portability courtesy Rick Spanbauer, WB2CFV
*/
#define SLOWCHECK
#ifdef SLOWCHECK
/*
* Word aligned linear buffer checksum routine. Called from mbuf checksum
* routine with simple args. Intent is that this routine may be replaced
* by assembly language routine for speed if so desired.
*/
static int16
lcsum(sum, wp, len)
register int32 sum;
register int16 *wp;
int16 len;
{
register int16 csum;
while(len-- != 0)
sum += *wp++;
while((csum = sum >> 16) != 0)
sum = csum + (sum & 0xffff);
return sum & 0xffff;
}
#endif SLOWCHECK
/* Perform end-around-carry adjustment */
static int16
eac(sum)
register int32 sum; /* Carries in high order 16 bits */
{
register int16 csum;
while((csum = sum >> 16) != 0)
sum = csum + (sum & 0xffff);
return sum; /* Chops to 16 bits */
}
/* Checksum a mbuf chain, with optional pseudo-header */
int16
cksum(ph,m,len)
struct pseudo_header *ph;
register struct mbuf *m;
int16 len;
{
register unsigned int cnt, total;
register int32 sum, csum;
register unsigned char *up;
sum = 0l;
/* Sum pseudo-header, if present */
if(ph != NULLHEADER){
sum = hiword(ph->source);
sum += loword(ph->source);
sum += hiword(ph->dest);
sum += loword(ph->dest);
sum += ph->protocol & 0xff;
sum += ph->length;
/* Swapping the sum is equivalent to summing the swapped
* elements, but faster. Do end-around-carry first.
*/
sum = htons(eac(sum));
}
/* Now do each mbuf on the chain */
for(total = 0; m != NULLBUF && total < len; m = m->next) {
cnt = min(m->cnt, len - total);
up = (unsigned char *)m->data;
/* Handle odd leading byte */
if(((long)up) & 1){
csum = (int16)ntohs(*up++);
cnt--;
} else
csum = 0;
/* Handle odd trailing byte */
if(cnt & 1)
csum += (int16)ntohs(up[--cnt]<<8);
if(cnt != 0){
/* Have the primitive checksumming routine do most of
* the work. At this point, up is guaranteed to be on
* a short boundary and cnt is guaranteed to be even
*/
csum = lcsum(csum, (unsigned short *)up, cnt >> 1);
}
/* If the mbuf we just did wasn't on a word boundary within
* the whole packet, then byteswap the checksum for this mbuf
*/
if((total&1) ^ (((long)m->data)&1)){
csum = eac(csum);
csum = (csum >> 8) + ((csum&0xff) << 8);
}
sum += csum;
total += m->cnt;
}
/* Do final end-around carry, complement and return */
return ~eac(sum) & 0xffff;
}
#ifdef TRACE
#include "trace.h"
void
ip_dump(bp)
struct mbuf *bp;
{
void tcp_dump(),udp_dump(),icmp_dump();
register struct ip_header *ip;
int32 source,dest;
int16 ip_len;
int16 length;
struct mbuf *tbp;
int16 offset;
int i;
int check;
char tmpbuf;
if(bp == NULLBUF)
return;
/* If packet isn't in a single buffer, make a temporary copy and
* note the fact so we free it later
*/
if(bp->next != NULLBUF){
bp = copy_p(bp,len_mbuf(bp));
tmpbuf = 1;
} else
tmpbuf = 0;
ip = (struct ip_header *)bp->data;
ip_len = lonibble(ip->v_ihl) * sizeof(int32);
length = ntohs(ip->length);
offset = (ntohs(ip->fl_offs) & F_OFFSET) << 3 ;
source = ntohl(ip->source);
dest = ntohl(ip->dest);
printf("IP: %s",inet_ntoa(source));
printf("->%s len %u ihl %u ttl %u prot %u",
inet_ntoa(dest),length,ip_len,ip->ttl & 0xff,
ip->protocol & 0xff);
if(ip->tos != 0)
printf(" tos %u",ip->tos);
if(offset != 0 || (ntohs(ip->fl_offs) & MF))
printf(" id %u offs %u",ntohs(ip->id),offset);
if(ntohs(ip->fl_offs) & DF)
printf(" DF");
if(ntohs(ip->fl_offs) & MF){
printf(" MF");
check = 0; /* Bypass host-level checksum verify */
} else {
check = 1;
}
if((i = cksum(NULLHEADER,bp,ip_len)) != 0)
printf(" CHECKSUM ERROR (%u)",i);
printf("\r\n");
if((trace & TRACE_HDR) > 3){
if(offset == 0){
dup_p(&tbp,bp,ip_len,length - ip_len);
switch(ip->protocol & 0xff){
case TCP_PTCL:
tcp_dump(tbp,source,dest,check);
break;
case UDP_PTCL:
udp_dump(tbp,source,dest,check);
break;
case ICMP_PTCL:
icmp_dump(tbp,source,dest,check);
break;
}
free_p(tbp);
}
}
if(tmpbuf)
free_p(bp);
fflush(stdout);
}
/* Dump IP routing table
* Dest Length Interface Gateway Metric
* 192.001.002.003 32 sl0 192.002.003.004 4
*/
int
dumproute()
{
register unsigned int i,bits;
register struct route *rp;
printf("Dest Length Interface Gateway Metric\r\n");
if(r_default.interface != NULLIF){
printf("default 0 %-13s",
r_default.interface->name);
if(r_default.gateway != 0)
printf("%-17s",inet_ntoa(r_default.gateway));
else
printf("%-17s","");
printf("%6u\r\n",r_default.metric);
}
for(bits=1;bits<=32;bits++){
for(i=0;i<NROUTE;i++){
for(rp = routes[bits-1][i];rp != NULLROUTE;rp = rp->next){
printf("%-18s",inet_ntoa(rp->target));
printf("%-10u",bits);
printf("%-13s",rp->interface->name);
if(rp->gateway != 0)
printf("%-17s",inet_ntoa(rp->gateway));
else
printf("%-17s","");
printf("%6u\r\n",rp->metric);
}
}
}
return 0;
}
#endif
SHAR_EOF
cat << \SHAR_EOF > telnetp.c
#include <stdio.h>
#include <exec/types.h>
#include <exec/nodes.h>
#include <exec/lists.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#include <exec/libraries.h>
#include <exec/io.h>
#include <exec/devices.h>
#include <exec/errors.h>
#include <proto/exec.h>
#include <devices/console.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <intuition/intuition.h>
#include <dos.h>
#include "machdep.h"
#include "mbuf.h"
#include "timer.h"
#include "internet.h"
#include "icmp.h"
#include "netuser.h"
#include "tcp.h"
#include "telnet.h"
#include "session.h"
#include "inetdev.h"
#include "inetlib.h"
#define DEBUG
struct Process *mytask;
APTR oldwindowptr;
struct IntuitionBase *IntuitionBase;
char banner[80] = "telnet window";
static struct NewWindow nw = {
0, 0, 640, 200, /* left, top, (max) width, (max) height */
0, 1, /* detail pen, block pen */
0, /* IDCMP flags */
SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH | WINDOWSIZING |
SIZEBBOTTOM | ACTIVATE | NOCAREREFRESH, /* window flags */
NULL, NULL, /* gadget, checkmark */
(UBYTE *)&banner[0], /* title of window */
NULL, NULL, /* screen, bitmap */
200, 50, -1, -1, /* sizing limits */
WBENCHSCREEN, /* on the workbench */
};
struct Window *win;
struct MsgPort *keyboard, *consinp, *consoutp, *tcpinp, *tcpoutp;
struct IOStdReq consin, consout;
char InputCharacter;
int deviceopened = 0;
struct IOINETReq tnreq, tninreq, tnoutreq;
char recv[512], snd[512];
struct telnet *tn;
#ifdef LATTICE
extern struct { short error; char *msg; } os_errlist[];
extern int _OSERR, os_nerr;
#endif
static
clean(why)
char *why;
{
int i;
InputCharacter = ' ';
while (InputCharacter != '<')
if (kbread() > 0)
amigaputchar(InputCharacter);
if (win)
CloseWindow(win);
if (consinp)
DeletePort(consinp);
if (consoutp)
DeletePort(consoutp);
if (tcpinp)
DeletePort(tcpinp);
if (tcpoutp)
DeletePort(tcpoutp);
if (deviceopened)
CloseDevice(&tnreq);
mytask->pr_WindowPtr = oldwindowptr;
if (why) {
myoserr(why);
}
exit(0);
}
printlist(l)
struct List *l;
{
printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail,
l->lh_TailPred);
}
myoserr(why)
char *why;
{
int i;
fprintf(stderr, "%s: ", why);
#ifdef LATTICE
fprintf(stderr, "%d: ", _OSERR);
for(i = 0; os_errlist[i].error < os_nerr; i++)
if (os_errlist[i].error == _OSERR)
fprintf(stderr, os_errlist[i].msg);
#endif
fprintf(stderr, "\r\n");
}
/* Called at startup time to set up console I/O, memory heap */
ioinit()
{
struct Screen *scr;
mytask = (struct Process *) FindTask((char *) NULL);
oldwindowptr = mytask->pr_WindowPtr;
mytask->pr_WindowPtr = (APTR) -1; /* disable DOS requestors */
if ((IntuitionBase = (struct IntuitionBase *)
OpenLibrary("intuition.library", 33L)) == NULL)
clean("No intuition: Version 1.2 of Amiga Systems Software required");
/*
* Try to determine the size of the workbench screen
*/
scr = malloc(sizeof(struct Screen));
if (scr==NULL)
clean("Can't alloc screen");
if (GetScreenData(scr, (ULONG) sizeof(struct Screen),
WBENCHSCREEN, NULL) == TRUE) {
nw.Width = scr->Width;
nw.Height = scr->Height-20;
nw.TopEdge = 19;
} else
fprintf(stderr, "Can't GetScreenData()\n");
free((char *)scr);
if ((win = OpenWindow(&nw)) == NULL)
clean("Can't open window");
if ((consinp = CreatePort("telnet:console in", 0L)) == NULL)
clean("Can't create console port");
if ((tcpinp = CreatePort("telnet:tcp in", 0L)) == NULL)
clean("Can't create telnet tcp input port");
if ((tcpoutp = CreatePort("telnet:tcp out", 0L)) == NULL)
clean("Can't create telnet tcp output port");
consin.io_Data = (APTR) win;
consin.io_Length = sizeof(struct Window);
_OSERR = OpenDevice("console.device", 0L, &consin, 0L);
if (_OSERR != 0L){
printf("opendevice returned %d\n", _OSERR);
myoserr("could not get console");
clean("Can't open console device");
}
consout = consin;
consin.io_Message.mn_ReplyPort = consinp;
consin.io_Length = 1;
consin.io_Data = (APTR) &InputCharacter;
consin.io_Command = CMD_READ;
SendIO(&consin);
consout.io_Message.mn_ReplyPort = consoutp;
consout.io_Command = CMD_WRITE;
}
/* Read characters from the keyboard, translating them to "real" ASCII
* If none are ready, return the -1 from kbraw()
*/
kbread()
{
char c;
if (CheckIO(&consin)) {
WaitIO(&consin);
c = InputCharacter;
consin.io_Length = 1;
consin.io_Data = (APTR) &InputCharacter;
consin.io_Command = CMD_READ;
SendIO(&consin); /* start next read up */
return (c & 0xff);
}
return -1; /* nuthin here */
}
extern char nospace[];
int refuse_echo = 0;
int unix_line_mode = 0; /* if true turn <cr> to <nl> when in line mode */
#ifdef DEBUG
char *t_options[] = {
"Transmit Binary",
"Echo",
"",
"Suppress Go Ahead",
"",
"Status",
"Timing Mark"
};
#endif
/* Telnet receiver upcall routine */
void
rcv_char()
{
/*printf("rcv_char: %d\n", tninreq.io_Actual);*/
tel_input(tn,tninreq.io_Data, tninreq.io_Actual);
fflush(stdout);
}
brk()
{
clean("ok i iwll quit\n");
}
/* TCP connection states */
char *tcpstates[] = {
"Closed",
"Listen",
"SYN sent",
"SYN received",
"Established",
"FIN wait 1",
"FIN wait 2",
"Close wait",
"Closing",
"Last ACK",
"Time wait"
};
/* TCP segment header flags */
char *tcpflags[] = {
"FIN", /* 0x01 */
"SYN", /* 0x02 */
"RST", /* 0x04 */
"PSH", /* 0x08 */
"ACK", /* 0x10 */
"URG" /* 0x20 */
};
/* TCP closing reasons */
char *reasons[] = {
"Normal",
"Reset",
"Timeout",
"ICMP"
};
char old = LISTEN;
int done = 0;
char *hostname="";
int hostport=0;
char *bannerfmt = "telnet %10s %4d %10s";
void
showstate(old, new)
char old, new;
{
/* extern char *tcpstates[];
extern char *reasons[];
extern char *unreach[];
extern char *exceed[];
*/
/* Can't add a check for unknown connection here, it would loop
* on a close upcall! We're just careful later on.
*/
sprintf(banner, bannerfmt, hostname, hostport, tcpstates[new]);
SetWindowTitles(win, banner, -1);
switch(new){
case CLOSE_WAIT:
done = 1;
break;
case CLOSED: /* court adjourned */
/* printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
if(tcb->reason == NETWORK){
switch(tcb->type){
case DEST_UNREACH:
printf(": %s unreachable",unreach[tcb->code]);
break;
case TIME_EXCEED:
printf(": %s time exceeded",exceed[tcb->code]);
break;
}
}
printf(")\r\n");
*/
done = 1;
break;
default:
break;
}
fflush(stdout);
}
/* Execute user telnet command */
main(argc,argv)
int argc;
char *argv[];
{
extern int _OSERR;
struct InternetBase *InternetBase;
int send_tel();
int unix_send_tel();
struct session *s;
/* struct tcb *tcb = NULL;*/
struct socket lsocket,fsocket;
ioinit();
hostname = argv[1];
old = LISTEN;
showstate(old, LISTEN);
tnreq.io_fsocket.address = aton(argv[1]);
if(argc < 3)
tnreq.io_fsocket.port = TELNET_PORT;
else
tnreq.io_fsocket.port = atoi(argv[2]);
tnreq.io_Device = NULL;
tnreq.io_Unit = NULL;
tnreq.io_Flags = 0;
tnreq.io_Error = 0;
InternetBase = (struct InternetBase *) OpenDevice("internet.device",
(long) INET_UNIT_TCP, &tnreq, 0L);
if (InternetBase != 0L){
printf("it did not open %d\n",InternetBase);
clean("i quit");
}
/* tcb = (struct tcb *) tnreq.io_Unit->iu_ccb;*/
hostport = tnreq.io_lsocket.port;
deviceopened = 1;
tninreq = tnreq; /* possible lettuce bug ?*/
tnoutreq = tnreq;
tninreq.io_Length = 512;
tnoutreq.io_Length = 1;
tninreq.io_Data = recv;
tnoutreq.io_Data = &InputCharacter;
tninreq.io_Command = CMD_READ;
tnoutreq.io_Command = CMD_WRITE;
tninreq.io_Message.mn_ReplyPort = tcpinp;
tnoutreq.io_Message.mn_ReplyPort = tcpoutp;
/* Create and initialize a Telnet protocol descriptor */
if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
myoserr("calloc faiuled\n");
goto done;
}
tn->session = s; /* Upward pointer */
tn->state = TS_DATA;
SendIO(&tninreq);
onbreak(&brk);
InputCharacter = ' ';
while (! done)
{
if ((snd[0] = kbread()) >= 0){
unix_send_tel(snd, (short) 1);}
if (CheckIO(&tninreq))
{
chkabort();
WaitIO(&tninreq);
rcv_char();
if (tninreq.io_State != old)
{
showstate(old, tninreq.io_State);
old = tninreq.io_State;
}
SendIO(&tninreq);
}
}
done:
clean("All done");
#ifdef NOTDEF
/* Allocate a session descriptor */
if((s = newsession()) == NULLSESSION){
printf("Too many sessions\r\n");
return 1;
}
s->type = TELNET;
if ((refuse_echo == 0) && (unix_line_mode != 0)) {
s->parse = unix_send_tel;
} else {
s->parse = send_tel;
}
current = s;
/* Create and initialize a Telnet protocol descriptor */
if((tn = (struct telnet *)calloc(1,sizeof(struct telnet))) == NULLTN){
printf(nospace);
s->type = FREE;
return 1;
}
tn->session = s; /* Upward pointer */
tn->state = TS_DATA;
s->cb.telnet = tn; /* Downward pointer */
tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,0,
rcv_char,NULLVFP,t_state,0,(int *)tn);
if(tcb == NULLTCB || tcb->state == CLOSED){
/* This is actually a bit dirty here. About the only time the
* state will be closed here is if we tried to connect to
* ourselves and got RST'ed. If this is true then the close
* upcall will already have freed the TCB and telnet block,
* so we're looking at the TCB after it's back on the heap.
*/
return 0;
}
tn->tcb = tcb; /* Downward pointer */
go();
return 0;
#endif
}
/* Process typed characters */
int
unix_send_tel(buf,n)
char *buf;
int16 n;
{
int i;
/*printf("unix_send_tel: buf[0] %d\n", buf[0]);*/
for (i=0; (i<n) && (buf[i] != '\r'); i++)
;
if (buf[i] == '\r') {
buf[i] = '\n';
n = i+1;
}
send_tel(buf,n);
}
int
send_tel(buf,n)
char *buf;
int16 n;
{
int i;
tnoutreq.io_Data = buf;
tnoutreq.io_Length = n;
SendIO(&tnoutreq);
/* printf("now waitio insend_tel: ");*/
i = WaitIO(&tnoutreq);
/*printf("send_tel: WaitIo is %d\n", i);*/
if (tnoutreq.io_State != old)
{
showstate(old, tnoutreq.io_State);
old = tnoutreq.io_State;
}
}
/* Process incoming TELNET characters */
int
tel_input(tn,bp, len)
register struct telnet *tn;
char *bp;
int len;
{
char c;
int ci;
void doopt(),dontopt(),willopt(),wontopt(),answer();
#ifdef FAST /* DON'T USE -- Aztec memchr() routine is broken */
char *memchr();
/* Optimization for very common special case -- no command chars */
if(tn->state == TS_DATA){
while(bp != NULLBUF && memchr(bp->data,IAC,bp->cnt)
== NULLCHAR){
fflush(stdout);
write(1,bp->data,bp->cnt);
bp = free_mbuf(bp);
}
}
#endif
while(len--){
c = *bp++;
ci = c & 0xff;
switch(tn->state){
case TS_DATA:
if(ci == IAC){
tn->state = TS_IAC;
} else {
if(!tn->remote[TN_TRANSMIT_BINARY])
c &= 0x7f;
putchar(c);
}
break;
case TS_IAC:
switch(ci){
case WILL:
tn->state = TS_WILL;
break;
case WONT:
tn->state = TS_WONT;
break;
case DO:
tn->state = TS_DO;
break;
case DONT:
tn->state = TS_DONT;
break;
case IAC:
putchar(c);
tn->state = TS_DATA;
break;
default:
tn->state = TS_DATA;
break;
}
break;
case TS_WILL:
willopt(tn,ci);
tn->state = TS_DATA;
break;
case TS_WONT:
wontopt(tn,ci);
tn->state = TS_DATA;
break;
case TS_DO:
doopt(tn,ci);
tn->state = TS_DATA;
break;
case TS_DONT:
dontopt(tn,ci);
tn->state = TS_DATA;
break;
}
}
}
#ifdef NOTDEF
/* State change upcall routine */
void
t_state(tcb,old,new)
register struct tcb *tcb;
char old,new;
{
struct telnet *tn;
char notify = 0;
extern char *tcpstates[];
extern char *reasons[];
extern char *unreach[];
extern char *exceed[];
/* Can't add a check for unknown connection here, it would loop
* on a close upcall! We're just careful later on.
*/
tn = (struct telnet *)tcb->user;
if(current != NULLSESSION && current->type == TELNET && current->cb.telnet == tn)
notify = 1;
switch(new){
case CLOSE_WAIT:
if(notify)
printf("%s\r\n",tcpstates[new]);
close_tcp(tcb);
break;
case CLOSED: /* court adjourned */
if(notify){
printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
if(tcb->reason == NETWORK){
switch(tcb->type){
case DEST_UNREACH:
printf(": %s unreachable",unreach[tcb->code]);
break;
case TIME_EXCEED:
printf(": %s time exceeded",exceed[tcb->code]);
break;
}
}
printf(")\r\n");
cmdmode();
}
del_tcp(tcb);
if(tn != NULLTN)
free_telnet(tn);
break;
default:
if(notify)
printf("%s\r\n",tcpstates[new]);
break;
}
fflush(stdout);
}
#endif
/* Delete telnet structure */
static
free_telnet(tn)
struct telnet *tn;
{
if(tn != NULLTN)
free((char *)tn);
}
/* The guts of the actual Telnet protocol: negotiating options */
static
void
willopt(tn,opt)
struct telnet *tn;
int opt;
{
int ack;
void answer();
#ifdef DEBUG
printf("recv: will ");
if(opt <= NOPTIONS)
printf("%s\r\n",t_options[opt]);
else
printf("%u\r\n",opt);
#endif
switch(opt){
case TN_TRANSMIT_BINARY:
case TN_ECHO:
case TN_SUPPRESS_GA:
if(tn->remote[opt] == 1)
return; /* Already set, ignore to prevent loop */
if(opt == TN_ECHO){
if(refuse_echo){
/* User doesn't want to accept */
ack = DONT;
break;
} else
raw(); /* Put tty into raw mode */
}
tn->remote[opt] = 1;
ack = DO;
break;
default:
ack = DONT; /* We don't know what he's offering; refuse */
}
answer(tn,ack,opt);
}
static
void
wontopt(tn,opt)
struct telnet *tn;
int opt;
{
void answer();
#ifdef DEBUG
printf("recv: wont ");
if(opt <= NOPTIONS)
printf("%s\r\n",t_options[opt]);
else
printf("%u\r\n",opt);
#endif
if(opt <= NOPTIONS){
if(tn->remote[opt] == 0)
return; /* Already clear, ignore to prevent loop */
tn->remote[opt] = 0;
if(opt == TN_ECHO)
cooked(); /* Put tty into cooked mode */
}
answer(tn,DONT,opt); /* Must always accept */
}
static
void
doopt(tn,opt)
struct telnet *tn;
int opt;
{
void answer();
int ack;
#ifdef DEBUG
printf("recv: do ");
if(opt <= NOPTIONS)
printf("%s\r\n",t_options[opt]);
else
printf("%u\r\n",opt);
#endif
switch(opt){
#ifdef FUTURE /* Use when local options are implemented */
if(tn->local[opt] == 1)
return; /* Already set, ignore to prevent loop */
tn->local[opt] = 1;
ack = WILL;
break;
#endif
default:
ack = WONT; /* Don't know what it is */
}
answer(tn,ack,opt);
}
static
void
dontopt(tn,opt)
struct telnet *tn;
int opt;
{
void answer();
#ifdef DEBUG
printf("recv: dont ");
if(opt <= NOPTIONS)
printf("%s\r\n",t_options[opt]);
else
printf("%u\r\n",opt);
#endif
if(opt <= NOPTIONS){
if(tn->local[opt] == 0){
/* Already clear, ignore to prevent loop */
return;
}
tn->local[opt] = 0;
}
answer(tn,WONT,opt);
}
static
void
answer(tn,r1,r2)
struct telnet *tn;
int r1,r2;
{
struct mbuf *bp,*qdata();
char s[3];
#ifdef DEBUG
switch(r1){
case WILL:
printf("sent: will ");
break;
case WONT:
printf("sent: wont ");
break;
case DO:
printf("sent: do ");
break;
case DONT:
printf("sent: dont ");
break;
}
if(r2 <= 6)
printf("%s\r\n",t_options[r2]);
else
printf("%u\r\n",r2);
#endif
s[0] = IAC;
s[1] = r1;
s[2] = r2;
tnoutreq.io_Data = s;
tnoutreq.io_Length = 3;
DoIO(&tnoutreq);
/*
bp = qdata(s,(int16)3);
send_tcp(tn->tcb,bp);
*/
}
#define BUFMAXCNT 150
static char conbuf[BUFMAXCNT];
static int concnt = 0;
int
amigaputchar(c)
char c;
{
conbuf[concnt++] = c;
if ((c == '\n') || (concnt == BUFMAXCNT))
amigaflush();
return c;
}
amigaflush()
{
if (concnt == 0)
return;
consout.io_Data = (APTR) conbuf;
consout.io_Length = concnt;
consout.io_Command = CMD_WRITE;
DoIO(&consout);
concnt = 0;
}
/*
* Begin terrible, horrible hack. All output should be printed upon (into?)
* the window we opened before. Here goes nothing...
*/
printf(a, b, c, d, e, f, g, h, i, j, k)
char *a;
int b, c, d, e, f, g, h, i, j, k;
{
if (concnt)
amigaflush();
sprintf(conbuf, a, b, c, d, e, f, g, h, i, j, k);
consout.io_Data = (APTR) conbuf;
consout.io_Length = strlen(conbuf);
consout.io_Command = CMD_WRITE;
DoIO(&consout); /* no use in doing this async */
}
SHAR_EOF
# End of shell archive
exit 0
--
Bob Page, U of Lowell CS Dept. page@swan.ulowell.edu ulowell!page
Have five nice days.